package rawengine.graphics.animation;

import java.util.Vector;

import rawengine.gamecore.GameCore;
import rawengine.graphics.Texture;
import rawengine.timer.TimeAccumulator;




/**
    The Animation class manages a series of images (frames) and
    the amount of time to display each frame.
*/
public class Animation {

	
    private Vector<AnimFrame> frames;
    private int characterWidth;
    private int characterHeight;
    private int currFrameIndex;
    private long totalDuration;
    private TimeAccumulator timeAccum;
 
    private AnimationState state;
    
    private String name;
    
    private Texture image;
    
        
    /**
        Creates a new, empty Animation.
    */
    public Animation(String name, int characterWidth, int characterHeight) 
    {
    	this(name, characterWidth, characterHeight, new Vector<AnimFrame>(), 0);
    }


    private Animation(String name, int characterWidth, int characterHeight, Vector<AnimFrame> frames, long totalDuration) 
    {
    	this.setName(name);
    	this.characterWidth = characterWidth;
    	this.characterHeight = characterHeight;
    	this.frames = frames;
        timeAccum = new TimeAccumulator();
        timeAccum.init(GameCore.timeHandler, totalDuration);
        this.totalDuration = totalDuration;
        this.setState(AnimationState.NORMAL);
        start();
        
    }
    
    


    /**
        Creates a duplicate of this animation. The list of frames
        are shared between the two Animations, but each Animation
        can be animated independently.
    */
    public Object clone() {
        return new Animation(name, characterWidth, characterHeight, frames, totalDuration);
    }

    

    /**
        Adds an image to the animation with the specified
        duration (time to display the image).
    */
    public synchronized void addFrame(int index, long duration, AnimFrame frame)
    {
        totalDuration += duration;
        AnimFrame frameClone = (AnimFrame) frame.clone();
        frameClone.setIndex(index);
        frameClone.setEndTime(totalDuration);
        frames.add(frameClone);
        timeAccum.setTimeLimit(totalDuration);
    }
    
    /**
    Adds an image to the animation with the specified
    duration (time to display the image).
	*/
	public synchronized void addFrame(int index, long duration, int characterWidth, int characterHeight)
	{
	    totalDuration += duration;
	    AnimFrame frame = new AnimFrame(image, index, characterWidth, characterHeight);
	    frame.setEndTime(totalDuration);
	    frames.add(frame);
	    timeAccum.setTimeLimit(totalDuration);
	}
	
    /**
    Adds an image to the animation with the specified
    duration (time to display the image).
	*/
	public synchronized void addFrame(int index, long duration)
	{
		if(image == null)
		{
			try {
				throw new Exception("Image must be set first");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	    totalDuration += duration;
	    AnimFrame frame = new AnimFrame(image, index, characterWidth, characterHeight);
	    frame.setEndTime(totalDuration);
	    frames.add(frame);
	    timeAccum.setTimeLimit(totalDuration);
	}


    /**
        Starts this animation over from the beginning.
    */
    public synchronized void start() 
    {
        currFrameIndex = 0;
    }


    /**
        Updates this animation's current image (frame), if
        necessary.
    */
    public synchronized void update() 
    {
        if (frames.size() > 1) 
        {
           
            timeAccum.update();
 
            if (timeAccum.ended()) 
            {
                timeAccum.restart();
                currFrameIndex = 0;
            }

            while (timeAccum.getTimeAccum() > getFrame(currFrameIndex).getEndTime()) 
            {
                currFrameIndex++;
            }
        }
    }



    public AnimFrame getFrame(int i) 
    {
        return frames.get(i);
    }
    
    public AnimFrame getCurrentFrame()
    {
    	return getFrame(currFrameIndex);
    }
    
    public int getAnimationSize()
    {
    	return frames.size();
    }

	/**
	 * @param state the state to set
	 */
	public void setState(AnimationState state) {
		this.state = state;
	}

	/**
	 * @return the state
	 */
	public AnimationState getState() {
		return state;
	}


	/**
	 * @param image the image to set
	*/ 
	public void setImage(Texture image) {
		this.image = image;
	}


	/**
	 * @return the image
	*/
	public Texture getImage() {
		return image;
	}


	/**
	 * @param name the name to set
	 */
	private void setName(String name) {
		this.name = name;
	}


	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}


}
